import requests
from django.conf import settings
import logging
from typing import Dict, List, Optional
from datetime import datetime, timedelta
import json
import asyncio
from asyncio import timeout
import jieba
import jieba.analyse

logger = logging.getLogger('apps')

class AIService:
    """AI 服务类"""
    def __init__(self):
        self.api_key = settings.AI_API_KEY
        self.api_base = settings.AI_API_BASE
        self.config = settings.AI_CONFIG
        self.request_queue = asyncio.Queue()
        self.batch_size = 5
        self.batch_timeout = 0.1  # 100ms

    async def process_requests(self):
        while True:
            batch = []
            try:
                # 收集请求批次
                async with timeout(self.batch_timeout):
                    while len(batch) < self.batch_size:
                        request = await self.request_queue.get()
                        batch.append(request)
            except asyncio.TimeoutError:
                pass
                
            if batch:
                # 批量处理请求
                responses = await self._batch_process(batch)
                
                # 分发响应
                for request, response in zip(batch, responses):
                    request['callback'](response)

    def _call_api(self, messages, temperature=0.7, max_tokens=1000):
        """调用 AI API"""
        try:
            headers = {
                'Authorization': f'Bearer {self.api_key}',
                'Content-Type': 'application/json'
            }
            
            data = {
                'model': self.config['model'],
                'messages': messages,
                'temperature': temperature,
                'max_tokens': max_tokens
            }
            
            response = requests.post(
                f'{self.api_base}/chat/completions',
                headers=headers,
                json=data,
                timeout=self.config['timeout']
            )
            
            response.raise_for_status()
            result = response.json()
            
            return result['choices'][0]['message']['content']
            
        except Exception as e:
            logger.error(f"AI API 调用失败: {str(e)}")
            raise

    def analyze_note(self, content: str) -> Dict:
        """分析笔记内容"""
        # 预处理文本
        cleaned_content = self._preprocess_text(content)
        
        messages = [
            {
                'role': 'system',
                'content': self.config['prompts']['analysis']['system']
            },
            {
                'role': 'user',
                'content': f'请分析以下笔记内容：\n\n{cleaned_content}'
            }
        ]
        
        result = self._call_api(
            messages, 
            temperature=self.config['temperature_presets']['precise']
        )
        return self._parse_analysis_result(result)

    def generate_summary(self, text: str, type: str = 'concise', language: str = 'zh') -> dict:
        """生成文本摘要
        
        Args:
            text (str): 需要总结的文本内容
            type (str): 摘要类型，可选值：concise/detailed/structured
            language (str): 语言，可选值：zh/en
            
        Returns:
            dict: 包含摘要和关键词的字典
        """
        try:
            # 构建提示词
            if type == 'concise':
                prompt = f"请简洁总结以下文本的主要内容：\n\n{text}"
            elif type == 'detailed':
                prompt = f"请详细总结以下文本的内容，包含主要观点和细节：\n\n{text}"
            else:  # structured
                prompt = f"请以结构化的方式总结以下文本，包含主题和要点：\n\n{text}"

            # 调用AI接口生成摘要
            response = self._call_api(
                messages=[
                    {
                        'role': 'system',
                        'content': '你是一个专业的文本摘要助手。'
                    },
                    {
                        'role': 'user',
                        'content': prompt
                    }
                ],
                temperature=0.7
            )

            # 提取关键词
            keywords = jieba.analyse.extract_tags(text, topK=10)

            return {
                'summary': response.strip(),
                'keywords': keywords
            }

        except Exception as e:
            logger.error(f"生成摘要失败: {str(e)}")
            raise

    def generate_plan(self, content, system_prompt=None, plan_type='exam', duration='week'):
        """生成计划"""
        try:
            # 如果没有提供system_prompt，使用默认提示
            if not system_prompt:
                system_prompt = self._get_default_plan_prompt(plan_type)

            # 构建消息列表
            messages = [
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": content}
            ]

            # 调用 DeepSeek API
            plan_text = self._call_api(
                messages=messages,
                temperature=0.7,
                max_tokens=1000
            )

            # 尝试解析JSON
            try:
                plan = json.loads(plan_text)
            except json.JSONDecodeError:
                plan = self._format_plan_response(plan_text, plan_type)

            # 添加元数据
            plan['metadata'] = {
                'generated_at': datetime.now().isoformat(),
                'plan_type': plan_type,
                'duration': duration
            }

            return plan

        except Exception as e:
            logger.error(f"生成计划失败: {str(e)}", exc_info=True)
            return None

    def _get_default_plan_prompt(self, plan_type):
        """获取默认的计划生成提示"""
        base_prompt = (
            "你是一个专业的日程规划助手，请根据提供的内容生成详细的计划安排。\n"
            "要求：\n"
            "1. 生成的计划必须包含：名称、日期、时间段、具体时间、优先级、描述\n"
            "2. 日期格式：MM月DD日\n"
            "3. 时间段：上午/下午\n"
            "4. 具体时间：HH:mm-HH:mm\n"
            "5. 优先级：高/中/低\n"
            "6. 按时间顺序排列\n"
            "7. 返回格式：\n"
            "{\n"
            '  "schedules": [\n'
            "    {\n"
            '      "name": "活动名称",\n'
            '      "date": "MM月DD日",\n'
            '      "time_period": "上午/下午",\n'
            '      "time": "HH:mm-HH:mm",\n'
            '      "priority": "高/中/低",\n'
            '      "description": "详细描述"\n'
            "    }\n"
            "  ],\n"
            '  "reminders": [\n'
            "    {\n"
            '      "type": "preparation/materials",\n'
            '      "content": "提醒内容",\n'
            '      "priority": "高/中/低"\n'
            "    }\n"
            "  ]\n"
            "}\n"
        )

        # 根据计划类型添加特定提示
        type_specific_prompts = {
            'exam': "\n考试计划特别注意：\n1. 合理安排考试时间间隔\n2. 标注考试地点和准备物品\n3. 添加考前准备提醒",
            'meeting': "\n会议安排特别注意：\n1. 安排会议室和与会人员\n2. 注意会议时长和间隔\n3. 添加会议准备材料提醒",
            'task': "\n任务计划特别注意：\n1. 考虑任务依赖关系\n2. 标注任务截止时间\n3. 添加任务进度提醒",
            'study': "\n学习计划特别注意：\n1. 合理分配学习时间\n2. 安排复习和练习\n3. 添加学习目标提醒"
        }

        return base_prompt + type_specific_prompts.get(plan_type, "")

    def _format_plan_response(self, response_text, plan_type):
        """格式化计划响应"""
        try:
            # 创建基本结构
            formatted_plan = {
                "schedules": [],
                "reminders": []
            }

            # 解析文本内容
            lines = response_text.split('\n')
            current_schedule = None

            for line in lines:
                line = line.strip()
                if not line:
                    continue

                if '：' in line or ':' in line:
                    if current_schedule:
                        formatted_plan['schedules'].append(current_schedule)
                    current_schedule = {
                        "name": "",
                        "date": "",
                        "time_period": "",
                        "time": "",
                        "priority": "中",
                        "description": ""
                    }
                    parts = line.split('：' if '：' in line else ':')
                    current_schedule['name'] = parts[0].strip()
                    if len(parts) > 1:
                        current_schedule['description'] = parts[1].strip()

            if current_schedule:
                formatted_plan['schedules'].append(current_schedule)

            return formatted_plan

        except Exception as e:
            logger.error(f"格式化计划响应失败: {str(e)}", exc_info=True)
            return None

    def process_schedule(self, content: str) -> Dict:
        """处理日程安排"""
        messages = [
            {
                'role': 'system',
                'content': """你是一个专业的日程处理助手。请从内容中提取以下信息：
1. 事项标题
2. 时间信息（开始时间、结束时间）
3. 优先级（高/中/低）
4. 相关人员
5. 需要准备的内容"""
            },
            {
                'role': 'user',
                'content': f'请处理以下日程内容：\n\n{content}'
            }
        ]
        
        result = self._call_api(messages, temperature=0.3)
        return self._parse_schedule_result(result)

    def _preprocess_text(self, text: str) -> str:
        """预处理文本"""
        # 1. 移除多余的空白字符
        text = ' '.join(text.split())
        
        # 2. 规范化标点符号
        text = self._normalize_punctuation(text)
        
        # 3. 处理特殊字符
        text = self._handle_special_chars(text)
        
        return text

    def _normalize_punctuation(self, text: str) -> str:
        """规范化标点符号"""
        # 实现标点符号规范化的逻辑
        punctuation_map = {
            '，': ',',
            '。': '.',
            '：': ':',
            '；': ';',
            '！': '!',
            '？': '?',
            '"': '"',
            '"': '"',
            ''': "'",
            ''': "'"
        }
        
        for cn, en in punctuation_map.items():
            text = text.replace(cn, en)
        
        return text

    def _handle_special_chars(self, text: str) -> str:
        """处理特殊字符"""
        # 1. 移除不可见字符
        text = ''.join(char for char in text if char.isprintable())
        
        # 2. 规范化空格
        text = text.replace('\t', ' ')
        text = text.replace('\n\n', '\n')
        
        return text

    def _parse_analysis_result(self, result: str) -> Dict:
        """解析分析结果"""
        try:
            sections = {
                '主要主题': 'topics',
                '关键要点': 'key_points',
                '建议标签': 'tags',
                '建议分类': 'category',
                '行动建议': 'suggestions'
            }
            
            analysis = {value: [] for value in sections.values()}
            current_section = None
            
            for line in result.split('\n'):
                line = line.strip()
                if not line:
                    continue
                    
                # 检查是否是新的部分
                section_found = False
                for cn_key, en_key in sections.items():
                    if line.startswith(cn_key):
                        current_section = en_key
                        section_found = True
                        break
                
                # 如果不是部分标题且有当前部分，则添加内容
                if not section_found and current_section:
                    # 处理不同类型的内容
                    if current_section == 'tags':
                        # 处理标签（去除空格和重复）
                        tags = [tag.strip() for tag in line.split(',')]
                        analysis[current_section].extend(
                            tag for tag in tags 
                            if tag and tag not in analysis[current_section]
                        )
                    elif current_section == 'category':
                        # 分类只保留最后一个值
                        analysis[current_section] = line
                    else:
                        # 其他部分作为列表项添加
                        if line.startswith(('-', '•', '*', '1.', '2.', '3.')):
                            line = line.lstrip('- •*123456789.').strip()
                        if line:
                            analysis[current_section].append(line)
            
            return analysis
            
        except Exception as e:
            logger.error(f"解析分析结果失败: {str(e)}")
            return {}

    def _parse_schedule_result(self, result: str) -> Dict:
        """解析日程结果"""
        try:
            lines = result.split('\n')
            schedule = {
                'title': '',
                'time': {
                    'start': '',
                    'end': ''
                },
                'priority': '',
                'participants': [],
                'preparations': []
            }
            
            current_section = None
            for line in lines:
                line = line.strip()
                if '标题' in line:
                    schedule['title'] = line.split('：')[-1].strip()
                elif '时间' in line:
                    time_info = line.split('：')[-1].strip()
                    if '至' in time_info:
                        start, end = time_info.split('至')
                        schedule['time']['start'] = start.strip()
                        schedule['time']['end'] = end.strip()
                elif '优先级' in line:
                    schedule['priority'] = line.split('：')[-1].strip()
                elif '相关人员' in line:
                    current_section = 'participants'
                elif '准备内容' in line:
                    current_section = 'preparations'
                elif line and current_section:
                    schedule[current_section].append(line)
            
            return schedule
            
        except Exception as e:
            logger.error(f"解析日程结果失败: {str(e)}")
            return {}

    def chat_completion(self, prompt, temperature=0.7, max_tokens=1000):
        """调用AI聊天接口"""
        try:
            messages = [
                {
                    'role': 'system',
                    'content': (
                        '你是一个专业的AI助手。如果要求返回JSON格式，'
                        '请确保只返回纯JSON内容，不要包含任何其他文字说明或代码块标记。'
                    )
                },
                {
                    'role': 'user',
                    'content': prompt
                }
            ]
            
            response = self._call_api(messages, temperature, max_tokens)
            
            # 如果提示中要求返回JSON格式，尝试提取和清理JSON
            if 'JSON格式' in prompt or 'json格式' in prompt.lower():
                # 尝试找到JSON的开始和结束位置
                start_idx = response.find('[')
                if start_idx == -1:
                    start_idx = response.find('{')
                end_idx = response.rfind(']')
                if end_idx == -1:
                    end_idx = response.rfind('}') + 1
                else:
                    end_idx += 1
                    
                if start_idx != -1 and end_idx > start_idx:
                    response = response[start_idx:end_idx]
                    
                # 移除可能的markdown代码块标记
                response = response.replace('```json', '').replace('```', '').strip()
            
            return response
            
        except Exception as e:
            logger.error(f"AI聊天接口调用失败: {str(e)}")
            return None

    def parse_json_response(self, response_text: str) -> Optional[Dict]:
        """解析 JSON 响应"""
        try:
            # 清理响应文本
            response_text = response_text.strip()
            # 移除可能的 markdown 代码块标记
            if response_text.startswith('```'):
                response_text = response_text.split('\n', 1)[1]
            if response_text.endswith('```'):
                response_text = response_text.rsplit('\n', 1)[0]
            if response_text.startswith('json'):
                response_text = response_text[4:].strip()
            response_text = response_text.strip()
            
            # 尝试解析 JSON
            result = json.loads(response_text)
            
            # 不再验证固定的必要字段，因为不同类型的响应有不同的字段要求
            return result
            
        except json.JSONDecodeError as e:
            logger.error(f"JSON 解析失败: {str(e)}\n响应内容: {response_text}")
            return None
        except Exception as e:
            logger.error(f"响应处理失败: {str(e)}")
            return None

    async def generate_personalized_suggestions(
        self,
        user_id: int,
        context_data: Dict
    ) -> Dict:
        """生成个性化建议
        
        Args:
            user_id: 用户ID
            context_data: 上下文数据
        """
        try:
            prompt = f"""
基于用户数据生成个性化建议：

用户数据：
{json.dumps(context_data, ensure_ascii=False)}

请提供：
1. 学习建议
2. 时间管理建议
3. 效率提升建议
4. 习惯养成建议
5. 下一步行动建议
"""
            response = await self._call_api(prompt)
            return self._parse_suggestions(response)
            
        except Exception as e:
            logger.error(f"生成个性化建议失败: {str(e)}")
            raise

    async def analyze_user_behavior(
        self,
        user_id: int,
        behavior_data: Dict
    ) -> Dict:
        """分析用户行为模式
        
        Args:
            user_id: 用户ID
            behavior_data: 行为数据
        """
        try:
            prompt = f"""
分析用户的行为模式：

行为数据：
{json.dumps(behavior_data, ensure_ascii=False)}

请提供：
1. 使用习惯分析
2. 效率模式识别
3. 潜在问题识别
4. 改进机会
5. 个性化建议
"""
            response = await self._call_api(prompt)
            return self._parse_behavior_analysis(response)
            
        except Exception as e:
            logger.error(f"分析用户行为失败: {str(e)}")
            raise